#include "client.h"

int EXIT_1;    // 主动
int EXIT_2;    // 被动
int chat_mode; // 聊天模式 1 群聊，2 私聊

IpList ipList;

// IP链表初始化
IpList InitIpList()
{
    IpList head = (IpList)malloc(sizeof(IpNode));
    if (head == (IpList)NULL)
    {
        perror("malloc ...");
        return (IpList)NULL;
    }
    memset(head, 0, sizeof(IpNode));
    head->next = NULL;
    return head;
}
// 添加IP到链表
void AddIpToIpList(IpList *head, const char *ip)
{
    if (FindIpInList(*head, ip) == NULL) // 检查IP是否已经存在
    {
        IpNode *newNode = (IpNode *)malloc(sizeof(IpNode));
        if (newNode == NULL)
        {
            perror("malloc failed");
            return;
        }
        strncpy(newNode->ip, ip, IP_LEN);
        newNode->next = *head;
        *head = newNode;
    }
}
// 遍历IP链表
void PrintIpList(IpList head)
{
    IpNode *current = head;
    int count = 0;
    printf("\n————————————————————————————————————\n");
    printf("|           在线用户列表           |\n");
    while (current->next != NULL)
    {
        printf("\n|       序号: %d                    |\n", ++count);
        printf("|       IP: %s          |\n", current->ip);
        current = current->next;
    }
    printf("————————————————————————————————————\n");
}
// 释放IP链表
void FreeIpList(IpList *head)
{
    IpNode *current = *head; // 获取头结点
    IpNode *temp;
    while (current != NULL) // 遍历释放节点
    {
        temp = current;
        current = current->next;
        free(temp);
    }
    *head = NULL;
}
// 在链表中查找IP地址
IpNode *FindIpInList(IpList head, const char *ip)
{
    IpNode *current = head;
    while (current != NULL)
    {
        if (strcmp(current->ip, ip) == 0)
        {
            return current; // 找到IP，返回节点
        }
        current = current->next;
    }
    return NULL; // 没有找到IP
}

// 发送消息任务函数
void *Send(void *arg)
{
    pthread_detach(pthread_self());
    int *cli_fd = (int *)arg;
    char msg[MSG_MAX_LEN];
    PrintIpList(ipList);
    while (1)
    {
        printf("\n————————————————————————————————————\n");
        printf("输入 exit 退出当前聊天\n");
        memset(msg, 0, MSG_MAX_LEN);
        printf("请输入要发送的消息：");
        if (scanf("%s", msg) != 1)
        {
            perror("scanf ....");
            break;
        }

        // 发送消息到服务器
        int msg_len = strlen(msg) + 1; // 包括 null 终止符
        if (chat_mode == 1)            // 群聊模式
        {
            if (write(*cli_fd, msg, msg_len) == -1)
            {
                perror("write ...");
                pthread_exit((void *)-1);
            }
        }
        else if (chat_mode == 2 && strcmp(msg, EXIT_MASK) != 0) // 私聊模式
        {
            int onlie_count = 0; // 在线用户个数
            IpNode *current = ipList;
            while (current->next != NULL)
            {
                onlie_count++;
                current = current->next;
            }

            if (onlie_count < 1)
            {
                printf("没有其他在线用户\n");
                sleep(2);
                break;
            }
            int targetIndex; // 目标客户端编号
            printf("目标客户端IP序号: ");
            scanf("%d", &targetIndex);

            if (targetIndex < 1 || targetIndex > onlie_count)
            {
                printf("无效的IP编号\n");
                sleep(2);
                break;
            }
            current = ipList;
            for (int i = 1; i < targetIndex; i++)
            {
                current = current->next;
            }
            // 发送私聊消息
            char private_msg[MSG_MAX_LEN + 30];
            snprintf(private_msg, sizeof(private_msg), "P_Chat:%s:%s", current->ip, msg);
            if (write(*cli_fd, private_msg, strlen(private_msg)) == -1)
            {
                perror("write ...");
                pthread_exit((void *)-1);
            }
            printf("-----------发送消息成功-----------\n");
        }

        if (strcmp(msg, EXIT_MASK) == 0) // 主动退出
        {
            break;
        }

        // printf("发送消息成功\n");
    }
    // 开启主动退出标志位
    EXIT_1 = 1;
    chat_mode = 0;
    pthread_exit((void *)0);
}

// 群聊任务函数
bool GroupChat_Task(int *cli_fd)
{
    int client_fd = *cli_fd;

    if (write(client_fd, WE_CHAT, strlen(WE_CHAT)) == -1)
    {
        perror("write ...");
        return false;
    }

    // 创建线程,用于发消息
    pthread_t send_id;
    if (pthread_create(&send_id, NULL, Send, (void *)&client_fd) != 0)
    {
        perror("pthread_create ...");
        return -1;
    }

    while (1)
    {
        if (EXIT_1 == 1)
        {
            if (pthread_cancel(send_id) != 0) // 取消发送消息的线程
            {
                perror("pthread_cancel ... ");
                return -1;
            }
            EXIT_1 = 0; // 重置标志位
            break;
        }
    }
    return true;
}
// 私聊任务函数
bool PrivateChat_Task(int *cli_fd)
{
    int client_fd = *cli_fd;

    // 创建线程,用于发消息
    pthread_t send_id;
    if (pthread_create(&send_id, NULL, Send, (void *)&client_fd) != 0)
    {
        perror("pthread_create ...");
        return -1;
    }

    while (1)
    {
        if (EXIT_1 == 1)
        {
            if (pthread_cancel(send_id) != 0) // 取消发送消息的线程
            {
                perror("pthread_cancel ... ");
                return -1;
            }
            EXIT_1 = 0; // 重置标志位
            break;
        }
    }

    return true;
}

// 接收服务器消息处理函数
void *Recv_server(void *arg)
{
    pthread_detach(pthread_self()); // 分离线程

    int *cli_fd = (int *)arg;
    char msg[MSG_MAX_LEN];

    ipList = InitIpList(); // 初始化IP链表

    while (EXIT_2)
    {
        memset(msg, 0, MSG_MAX_LEN);

        int ret = read(*cli_fd, msg, sizeof(msg) - 1);
        if (ret == -1)
        {
            perror("read ...");
            FreeIpList(&ipList); // 释放链表
            pthread_exit((void *)-1);
        }
        if (ret == 0 || strcmp(msg, EXIT_MASK) == 0)
        {
            printf("\n服务器已关闭!!!客户端退出\n");
            break;
        }

        msg[ret] = '\0'; // 确保字符串终止
        // printf("\n收到服务器消息：\n%s\n", msg);

        if (strstr(msg, "IP_LIST:") != 0) // 如果消息是在线IP列表
        {
            char *token = strtok(msg + 8, ","); // 分割消息头
            if (token == NULL)
            {
                continue;
            }

            // 清空链表并重新添加
            FreeIpList(&ipList);
            ipList = InitIpList();

            if (strstr(msg, "No") != 0) // 没有其他在线用户
            {
                printf("\n————————————————————————\n");
                printf("|   没有其他在线用户   |\n");
                printf("————————————————————————\n");
                continue;
            }

            while (token != NULL)
            {
                // 确保添加的 IP 不为空
                if (strlen(token) > 0)
                {
                    AddIpToIpList(&ipList, token); // 添加IP到链表
                }
                token = strtok(NULL, ",");
            }
            printf("\n当前在线用户列表：\n");
            PrintIpList(ipList); // 打印在线用户列表
        }
        else if (strstr(msg, "WEATHER:") != 0) // 如果消息是天气信息
        {
            char *weather_msg = msg + 8;
            weather_print(weather_msg);
        }
        else if (strstr(msg, "GROUP_C:") != 0) // 如果消息是群聊信息
        {
            char *group_msg = msg + 8;
            printf("\n收到来自群聊的消息：%s\n", group_msg);
        }
        else if (strstr(msg, "PRIVATE_MSG:") != 0) // 如果消息是私聊信息
        {
            char *private_msg = msg + 12;
            printf("\n收到私聊消息：\n%s\n", private_msg);
        }
        else if (strstr(msg, "TIME:") != 0) // 如果是时间信息
        {
            char *time_msg = msg + 5;
            printf("\n当前时间：%s\n", time_msg);
        }
    }
    EXIT_2 = 0;
    close(STDIN_FILENO); // 关闭标准输入
    FreeIpList(&ipList); // 释放链表
    close(*cli_fd);
    printf("\n^^^^^^^^资源已释放,客户端退出^^^^^^^^\n");
    pthread_exit((void *)0);
}

// 天气信息处理函数
void weather_print(char *weather_msg)
{
    char weather[256];
    char weather_text[276];
    char temp[256];
    char temp_text[276];
    // 使用 sscanf 从 weather_msg 中提取天气和温度信息
    int ret = sscanf(weather_msg, "Weather: %255[^,], Temp: %255[^C]", weather, temp);
    if (ret == 2)
    {
        // printf("Weather: %s, Temp: %s\n", weather, temp);
    }
    else
    {
        perror("sscanf failed");
    }
    sprintf(weather_text, "当前天气: %s", weather);
    sprintf(temp_text, "当前温度: %sC", temp);

    printf("\n————————————————————————\n");
    printf("|~~~~ %s ~~~~|\n", weather_text);
    printf("|~~~~ %s ~~|\n", temp_text);
    printf("————————————————————————\n");
}

// 功能选择界面显示
void show_Menu()
{
    printf("\n》》》》》》功能选择《《《《《《\n");
    printf("|           [1] 私聊           |\n");
    printf("|           [2] 群聊           |\n");
    printf("|           [3] 天气           |\n");
    printf("|           [4] 在线           |\n");
    printf("|           [5] 退出           |\n");
    printf("》》》》》》》》《《《《《《《《\n");
    printf("请输入功能序号：");
}

// 客户端主程序
int client()
{
    // 创建套接字
    int cli_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (cli_fd == -1)
    {
        perror("socket ...");
        return -1;
    }

    // 配置服务器网络信息的专属结构体变量
    struct sockaddr_in ser_inf;
    memset(&ser_inf, 0, sizeof(ser_inf));

    ser_inf.sin_family = AF_INET; // IPv4
    ser_inf.sin_port = htons(8888);
    ser_inf.sin_addr.s_addr = inet_addr("192.168.53.65"); // 服务器的IP地址

    // 连接服务器
    if (connect(cli_fd, (struct sockaddr *)&ser_inf, sizeof(ser_inf)) == -1)
    {
        perror("connect ...");
        printf("<<<<<<<<<连接服务器失败!>>>>>>>>>\n");
        close(cli_fd);
        return -1;
    }

    printf("\n<<<<<<<<<连接服务器成功>>>>>>>>>\n");

    // 创建线程接收服务器消息并处理
    pthread_t recv_ser_id;
    if (pthread_create(&recv_ser_id, NULL, Recv_server, (void *)&cli_fd) != 0)
    {
        perror("pthread_create ...");
        return -1;
    }

    EXIT_2 = 1;
    chat_mode = 0;

    int mode = 0;
    char input[MSG_MAX_LEN];
    while (EXIT_2)
    {
        show_Menu();
        fflush(stdout); // 确保输出被立即刷新
        if (fgets(input, sizeof(input), stdin) == NULL)
        {
            perror("fgets failed");
            continue;
        }
        if (sscanf(input, "%d", &mode) == 1)
        {
            switch (mode)
            {
            case 1: // 私聊
                chat_mode = 2;
                PrivateChat_Task(&cli_fd);
                break;

            case 2: // 群聊
                chat_mode = 1;
                GroupChat_Task(&cli_fd);
                break;

            case 3: // 天气
                if (write(cli_fd, SHOW_WEATHER, strlen(SHOW_WEATHER)) == -1)
                {
                    perror("write ...");
                    return -1;
                }
                break;

            case 4: // 在线
                if (write(cli_fd, SHOW_ONLINE_CLI, strlen(SHOW_ONLINE_CLI)) == -1)
                {
                    perror("write ...");
                    return -1;
                }
                break;

            case 5:
                EXIT_2 = 0;
                close(cli_fd);
                printf("\n^^^^^^^^资源已释放,客户端退出^^^^^^^^\n");
                break;

            default:
                printf("!!!无效输入!!!\n");
                break;
            }
        }
    }
    return 0;
}
